#include "image_network_reader.h"
#include "atlas_utils.h"
#include <sys/time.h>

namespace {
    const int64_t kUsec = 1000000;
}


namespace {
    const uint32_t kDecodeFrameQueueSize = 256;
    const int kReadQueueOpWait = 10000; //每次等待10毫秒
    const int kFrameEnQueueRetryTimes = 1000;//为了防止丢帧,入队最多等待 1ms
    const int kWaitReaderFinishInterval = 1000;
    
    // 来自发送端的UDP帧参数
    const int kBytesOfUdpDataHead = 20;     // UDP数据包中 有效数据 的帧头长度（此处为图像帧头）
    const int kBytesOfUdpData = 4096;       // 每个UDP数据包中 有效数据 的最大大小（不包括帧头）
    const int kBytesOfUdpFrameHead = 20;         // 每个UDP数据包中帧头的大小
    const int kBytesOfUdpFrame = kBytesOfUdpData + kBytesOfUdpFrameHead;   // UDP数据包的大小
    const int kUdpRecvBufSzie = 1024*10000;
    const char kip[] = "0.0.0.0";
    const int kport = 12008;

    const int kTcpRecvBufSzie = kBytesOfUdpData + kBytesOfUdpFrameHead;
}

ImageNetworkReader::ImageNetworkReader(const std::string& protocol, int port, aclrtContext context)
:context_(context)
,status_(READER_UNINIT)
,protocolName_(protocol)
,port_(port)
,frameImageQueue_(kDecodeFrameQueueSize)
,isStop_(false)
,isReleased_(false){
    // 如果输入的port不合适就采用默认值
    if (port_ > 65535 || port < 1000) {
        port_ = kport;
    }
}

ImageNetworkReader::~ImageNetworkReader() {
    DestroyResource();
}

void ImageNetworkReader::DestroyResource() {
    if (isReleased_) return;    
   
    isStop_ = true;

    dvpp_.DestroyResource();

    AtlasError ret;
    if (stream_ != nullptr) {
        ret = aclrtDestroyStream(stream_);
        if (ret != ACL_ERROR_NONE) {
            ERROR_LOG("destroy stream failed");
        }
        stream_ = nullptr;
    }
    INFO_LOG("end to destroy stream");

    while ((status_ >= READER_START) && (status_ < READER_FINISHED))
        usleep(kWaitReaderFinishInterval);

    
    do {
        shared_ptr<ImageData> frame = FrameImageOutQueue(true);
        if (frame == nullptr)  {
            break;
        }

        if (frame->data != nullptr) {
            acldvppFree(frame->data.get());
            frame->data = nullptr;
        }       
    }while(1);
    isReleased_ = true;
}

AtlasError ImageNetworkReader::InitResource() {
    aclError aclRet;

    if (context_ == nullptr) {
        aclRet = aclrtGetCurrentContext(&context_);
        if ((aclRet != ACL_ERROR_NONE) || (context_ == nullptr)) {
            ATLAS_LOG_ERROR("Get current acl context error:%d", aclRet);
            return ATLAS_ERROR_SET_ACL_CONTEXT;
        }       
    }
    
    //如果有传入acl context参数,设置解码器主线程context
    AtlasError ret = SetAclContext();
    if (ret != ATLAS_OK) {
        ATLAS_LOG_ERROR("Set video decoder acl context error:%d", aclRet);
        return ret;
    }

    aclRet = aclrtGetRunMode(&runMode_);
    if (aclRet != ACL_ERROR_NONE) {
        ATLAS_LOG_ERROR("acl get run mode failed");
        return ATLAS_ERROR_GET_RUM_MODE;
    } 
    

    return ATLAS_OK;  
}

AtlasError ImageNetworkReader::InitTcpSocket() {
    int fd;
    int optval = 1;
    // int nRecvBuf = kUdpRecvBufSzie;
    fd = socket(AF_INET, SOCK_STREAM, 0);
    if (fd == -1)
    {
        ERROR_LOG("fail to socket");
        return ATLAS_ERROR;
    }

    struct sockaddr_in server_addr;
    bzero(&server_addr, sizeof(server_addr));
    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(kip);
    server_addr.sin_port = htons(port_);

    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
                        (const void*)&optval, sizeof (optval));
    // setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
    //                     (const void*)&nRecvBuf, sizeof (nRecvBuf));
    int ret = bind(fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (ret < 0)
    {
        ERROR_LOG("fail to bind");
        close(fd);
        printf("%s\n", strerror(errno));
        return ATLAS_ERROR;
    }
    if (listen(fd, 5) < 0) {
        ERROR_LOG("listen error");
        close(fd);
        printf("%s\n", strerror(errno));
        return -1;
    }

    networkSocket_ = fd;
    INFO_LOG("image network reader thread tcp socket bind %s:%d success", kip, port_);
    return ATLAS_OK;
}

AtlasError ImageNetworkReader::InitUdpSocket() {
    int fd;
    int optval = 1;
    int nRecvBuf = kUdpRecvBufSzie;
    struct sockaddr_in server_addr;
    fd = socket(AF_INET, SOCK_DGRAM, 0);
    if (fd == -1)
    {
        ERROR_LOG("fail to socket");
        return ATLAS_ERROR;
    }

    bzero(&server_addr, sizeof(server_addr));

    server_addr.sin_family = AF_INET;
    server_addr.sin_addr.s_addr = inet_addr(kip);
    server_addr.sin_port = htons(port_);

    setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
                        (const void*)&optval, sizeof (optval));
    setsockopt(fd, SOL_SOCKET, SO_RCVBUF,
                        (const void*)&nRecvBuf, sizeof (nRecvBuf));
    int ret = bind(fd, (struct sockaddr *)&server_addr, sizeof(server_addr));
    if (ret < 0)
    {
        ERROR_LOG("fail to bind");
        printf("%s\n", strerror(errno));
        return ATLAS_ERROR;
    }
    networkSocket_ = fd;
    INFO_LOG("image network reader thread udp bind %s:%d success", kip, port_);
    return ATLAS_OK;
}

AtlasError ImageNetworkReader::Open() {
    //防止多次初始化
    if (status_ == READER_ERROR) 
        return ATLAS_ERROR_OPEN_IMAGE_READER_UNREADY;

    if (status_ != READER_UNINIT)
        return ATLAS_OK;

    AtlasError ret = InitResource();
    if (ret != ATLAS_OK) {
        this->SetStatus(READER_ERROR);
        ATLAS_LOG_ERROR("Open %s reader failed for init resource error: %d", 
                        protocolName_.c_str(), ret);
        return ret;
    }

    // create stream
    ret = aclrtCreateStream(&stream_);
    if (ret != ACL_ERROR_NONE) {
        ERROR_LOG("acl create stream failed");
        return FAILED;
    }
    INFO_LOG("create stream success");
    ret = dvpp_.InitResource(stream_);
    if (ret != ATLAS_OK) {
        this->SetStatus(READER_ERROR);
        ATLAS_LOG_ERROR("Open network reader failed for init dvpp error: %d", ret);
        return ret;
    }

    if (protocolName_ == "tcp") {
        ret = InitTcpSocket();
    } else if (protocolName_ == "udp") {
        ret = InitUdpSocket();
    } else {
        ret = InitUdpSocket();  // websocket in future
    }
    if (ret != ATLAS_OK) {
        this->SetStatus(READER_ERROR);
        ATLAS_LOG_ERROR("Bind %s socket failed for init resource error: %d", 
                        protocolName_.c_str(), ret);
        return ret;
    }
 
    this->SetStatus(READER_READY);
    ATLAS_LOG_INFO("Network %s reader init ok", protocolName_.c_str());

    return ATLAS_OK;
}




//启动ffmpeg解码器,将视频文件解码为h26x帧
void ImageNetworkReader::StartFrameReader() {
    if (status_ == READER_READY) {

        readerThread_ = thread(FrameReadThreadFunction, (void*)this);

        cpu_set_t cpuset;
        CPU_ZERO(&cpuset);
        CPU_SET(1, &cpuset);
        int rc =pthread_setaffinity_np(readerThread_.native_handle(),sizeof(cpu_set_t), &cpuset);
        if (rc != 0) {
            std::cerr << "Error calling pthread_setaffinity_np: " << rc << "\n";
        }

        if (readerThread_.joinable()) {
            readerThread_.detach();
            status_ = READER_START;
        } else {
            ATLAS_LOG_ERROR("StartFrameReader: thread not exist, status %d", status_);
        }

        
    }
}

//网络数据读取线程入口
void ImageNetworkReader::FrameReadThreadFunction(void* readerSelf) {
    ImageNetworkReader* thisPtr =  (ImageNetworkReader*)readerSelf;

    // 将网络数据读取线程的context设为和主线程一致
    aclError aclRet = thisPtr->SetAclContext();
    if (aclRet != ACL_ERROR_NONE) {
        ATLAS_LOG_ERROR("Set frame decoder context failed, errorno:%d",
                        aclRet);
        thisPtr->SetStatus(READER_ERROR);  
        return;
    }
    // 监听端口，这是一个阻塞接口，直到接收到结束信号，或者错误才返回
    if (thisPtr->protocolName_ == "tcp") {
        thisPtr->TcpNetworkRead(thisPtr);
    } else if (thisPtr->protocolName_ == "udp") {
        thisPtr->UdpNetworkRead(thisPtr);
    } else {
        thisPtr->UdpNetworkRead(thisPtr);  // websocket in future
    }
    thisPtr->SetStatus(READER_FINISHED);  
}

int KTable[256];
void buildSearchTable( const unsigned char* head, int length )
{
	static bool k = true;   //保证此函数之执行一次
	if(k)
	{
		for ( int i = 0; i < 256; i ++ )    //总体初始化为-1
			KTable[i] = -1;

		for ( int i = 0; i < length; i ++ )    //保存帧头字节的游标
			KTable[ head[i] ] = i;
		k = false;
	}
}

int searchHead2R(unsigned char* pData, int size, const unsigned char* frameHeader, int headerLength)
{
	int i = 0;//初始化游标
	int j = 0;
	int m = i + headerLength;

	while( i < size && j < headerLength )
	{
		if( pData[i] == frameHeader[j] )   //开始逐个比较
		{
			++i;
			++j;
		}
		else
		{
			j = 0;
			i = m - KTable[ pData[m] ];
			m = i + headerLength;
		}
	}

	if( i < size )
		return i - headerLength;
	return -1;
}

void ImageNetworkReader::TcpNetworkRead(ImageNetworkReader* thisPtr) 
{

    INFO_LOG("TCP Network Reader thread create");
    int bufLen = kTcpRecvBufSzie;

    int packSize = bufLen;
    uchar readBuffer[1024];

    uchar* readData = new uchar[2*bufLen];

    int hasReadPackSize = 0;
    const int headerLength = 4;
    
    uchar header[headerLength];
    for (int i = 0; i < UPD_FRAME_HEAD_SIZE; i++) {
        header[i] = (UDP_FRAME_HEAD >> i*8) & 0xff;
    }

    buildSearchTable(header, headerLength);

    // 保存上次读取的最后headerLength - 1个字节，避免header断在两次读取中
    const int lastCharsLength = headerLength - 1;   
	uchar lastChars[lastCharsLength] = { 0x00 };
    uchar* searchBuffer = new uchar[1024 + lastCharsLength];
    bool isGetHeader = false;

    while (true)
    {
        int n_sockfd;
        struct sockaddr_in cli;
        socklen_t nRecLen = sizeof(cli) ;

        n_sockfd = accept(thisPtr->networkSocket_, (struct sockaddr*)&cli, &nRecLen);
        if(n_sockfd<0){ 
            ATLAS_LOG_ERROR("accept error");
            continue;
        }

        while(true) {
            
            int readLen = recv(n_sockfd, readBuffer, sizeof(readBuffer), 0);
            // 被动关闭连接
            if (readLen <= 0) {
                break;
            }

            // 寻找帧头{ 0x24, 0x53, 0x44, 0x52 }
            if (!isGetHeader) {
                memcpy(searchBuffer, lastChars, lastCharsLength);
                memcpy(searchBuffer + lastCharsLength, readBuffer, readLen);

                //aa 55 aa 55 起始位置
                int pos = searchHead2R(searchBuffer, readLen + lastCharsLength, header, headerLength);

                if (pos != -1)
                {
                    isGetHeader = true;
                    // cout << "head" << endl;
                    memcpy(readData + hasReadPackSize, searchBuffer + pos, readLen - (pos - lastCharsLength));
                    hasReadPackSize = hasReadPackSize + readLen - (pos - lastCharsLength);
                }
                // 复制最后三个字节，避免帧头断开在两次读取中
                memcpy(lastChars, readBuffer + readLen - lastCharsLength, lastCharsLength);
                continue;
            }

            if (hasReadPackSize + readLen < packSize) {
                memcpy(readData + hasReadPackSize, readBuffer, readLen);
			    hasReadPackSize = hasReadPackSize + readLen;
            } else {

                int sizeFromPrePack = packSize - hasReadPackSize; // 当前帧还剩多少需要读
                memcpy(readData + hasReadPackSize, readBuffer, sizeFromPrePack);

                bool errorFlag = false;
                // 验证当前数据头是否是指定帧头，如果不是，则丢弃当前数据
                for (int i = 0; i < headerLength; i++) {
                    if (readData[i] != header[i]) {
                        errorFlag = true;
                        break;
                    }
                }
                if (errorFlag) {
                    //遇到帧头不对，直接重新找帧头
                    hasReadPackSize = 0;
                    isGetHeader = false;
                    memcpy(lastChars, readBuffer + readLen - lastCharsLength, lastCharsLength);
                    continue;
                }

                ReceiveDataProcess(readData);

                hasReadPackSize = readLen - sizeFromPrePack; // 本次读到的数据凑成一帧数据的同时还剩余多少
                if (hasReadPackSize != 0)  // 如果有剩余就把它归到下一帧中
                {
                    int pack_len = readData[7]<<(8*3) | readData[6]<<(8*2) | readData[5]<<8 | readData[4];
                    // printf("%x %x %x %x %d %d\n", readData[0], readData[1], readData[2], readData[3], 
                    // readData[7]<<(8*3) | readData[6]<<(8*2) | readData[5]<<8 | readData[4], hasReadPackSize+packSize-pack_len);
                    memcpy(readData, readData + pack_len, packSize - pack_len);
                    memcpy(readData + packSize - pack_len, readBuffer + sizeFromPrePack, hasReadPackSize);
                    hasReadPackSize += packSize - pack_len;   // may be larger than packSize
                    while (hasReadPackSize >= packSize)
                    {
                        ReceiveDataProcess(readData);
                        hasReadPackSize -= packSize;
                        memcpy(readData, readData + packSize, hasReadPackSize);
                    }
                    
                }
                
            }
        }
        hasReadPackSize = 0;
        isGetHeader = false;
        close(n_sockfd);
    }

	delete[] readData;
	delete[] searchBuffer;
}

void ImageNetworkReader::UdpNetworkRead(ImageNetworkReader* thisPtr) {

    INFO_LOG("UDP network reader thread create");
    unsigned char readData[32768];
    struct sockaddr_in cli;
    while (true)
    {
        socklen_t nRecLen = sizeof(cli) ;
        int ret = recvfrom(thisPtr->networkSocket_, readData, sizeof(readData), 0, (sockaddr*)&(cli), &(nRecLen));
        if(ret > 0)
        {
            ReceiveDataProcess(readData);
        }
        // usleep(1);   // 百兆网线连接下请设为1，typec连接下请注释该行
    }
}

Result ImageNetworkReader::ReceiveDataProcess(unsigned char* buf) {
    
    unsigned char* pointer;
    pointer = &buf[0];
    shared_ptr<UdpFrame> frame = make_shared<UdpFrame>();
    // 解head
    frame->head = pointer[3]<<(8*3) | pointer[2]<<(8*2) | pointer[1]<<8 | pointer[0];
    if(frame->head != UDP_FRAME_HEAD)
    {
        ATLAS_LOG_ERROR("head error %x", frame->head);
        return FAILED;
    }
    pointer += 4;

    // 解len
    frame->len = pointer[3]<<(8*3) | pointer[2]<<(8*2) | pointer[1]<<8 | pointer[0];
    if(frame->len > kBytesOfUdpFrame)
    {
        ATLAS_LOG_ERROR("len error");
        return FAILED;
    }
    pointer+=4;

    // 解id    
    frame->id = pointer[3]<<(8*3) | pointer[2]<<(8*2) | pointer[1]<<8 | pointer[0];
    if(frame->id != UDP_FRAME_ID)
    {
        ATLAS_LOG_ERROR("tail error");
        return FAILED;
    }
    pointer+=4;

    // 解seq
    frame->seq = pointer[1]<<8 | pointer[0];
    pointer+=2;

    // 解NUM
    frame->num = pointer[1]<<8 | pointer[0];
    if(frame->seq > frame->num)
    {
        ATLAS_LOG_ERROR("num error");
        return FAILED;
    }
    pointer += 2;

    // 解图像DATA
    memcpy(frame->frm_body.uint8, pointer, frame->len-kBytesOfUdpDataHead);
    pointer += frame->len-kBytesOfUdpDataHead;

    // 解TAIL
    frame->tail = pointer[2]<<(8*2) | pointer[1]<<8 | pointer[0];
    if(frame->tail != UDP_FRAME_TAIL) {
        ATLAS_LOG_ERROR("tail error");
        return FAILED;
    }
    pointer+=3;

    // 校验
    unsigned char t_check = 0;
    frame->check = pointer[0];
    for(int i = 8; i < (int)frame->len - 4; i++)
    {
        t_check += buf[i];
    }
    if(t_check != frame->check)
    {
        ATLAS_LOG_ERROR("check error");
        return FAILED;
    }

    Result ret = JpegImageDataProcess(frame, buf);
    if(ret == FAILED) {
        return FAILED;
    }
    return SUCCESS;

}

Result ImageNetworkReader::JpegImageDataProcess(shared_ptr<UdpFrame> &frame, unsigned char data[])
{
    if(frame->seq == 0) {
        unsigned short CRC = frame->frm_body.uint8[19]<<8 | frame->frm_body.uint8[18];
        if(CRC != Utils::Crc16Fast(frame->frm_body.uint8+2, 16, 0)) {
            ATLAS_LOG_ERROR("image frame crc error");
            return FAILED;
        }

        if(frame->frm_body.uint8[0] != 0x5A || frame->frm_body.uint8[1] != 0x4A || frame->frm_body.uint8[2] != 0x10) {
            ATLAS_LOG_ERROR("image frame head flag or len error");
            return FAILED;
        }

        image_id = frame->frm_body.uint8[7] << 24 | frame->frm_body.uint8[6] << 16 | frame->frm_body.uint8[5] << 8 | frame->frm_body.uint8[4];
        imageHeight_ = frame->frm_body.uint8[9]<<8 | frame->frm_body.uint8[8];
        imageWidth_ = frame->frm_body.uint8[11]<<8 | frame->frm_body.uint8[10];

        pre_image_seq = -1;
        
        jpegImageBufferSize_ = 0;
        jpegImageBuffer_.reset(new uint8_t[1024*1024], [](uint8_t* p) { delete[](p);});
    }
    
    // 在TCP可靠传输下，这个if一般是不会条件成立的
    if( frame->seq != (pre_image_seq+1) )
    {
        // cout << pre_image_seq << " " <<frame->seq << endl;
        // ATLAS_LOG_ERROR("image seq error");
        return FAILED;
    }

    pre_image_seq = frame->seq;

    if (frame->seq == 0) {
        memcpy(jpegImageBuffer_.get() + jpegImageBufferSize_,
            frame->frm_body.uint8 + kBytesOfUdpDataHead,
            frame->len - kBytesOfUdpDataHead);
        jpegImageBufferSize_ += frame->len - kBytesOfUdpDataHead - kBytesOfUdpFrameHead;
    } else {
        memcpy(jpegImageBuffer_.get() + jpegImageBufferSize_,
            frame->frm_body.uint8,
            frame->len);
        jpegImageBufferSize_ += frame->len - kBytesOfUdpFrameHead;
    }
    
    if (frame->seq == frame->num - 1) {
        return CreateInputImageData(jpegImageBuffer_, jpegImageBufferSize_, image_id);
    }


    return SUCCESS;
}

Result ImageNetworkReader::CreateInputImageData(const shared_ptr<uchar> buf, int bufsize, int id) {

    shared_ptr<ImageData> image = make_shared<ImageData>();
    image->height = imageHeight_;
    image->width = imageWidth_;
    image->data = buf;
    image->size = bufsize;

    // cout << bufsize << " " << imageHeight_ << " " << imageWidth_ << " " << id << endl;

    ImageData yuvImage, cropImage;
    ImageData dvppImage;

    AtlasError ret = Utils::CopyImageDataToDvpp(dvppImage, *image.get());
    if (ret == FAILED) {
        ERROR_LOG("CreateInputImageData: CopyImageDataToDvpp failed");
        return FAILED;
    }

    
    ret = dvpp_.JpegD(yuvImage, dvppImage);
    if (ret == FAILED) {
        ERROR_LOG("CreateInputImageData: JpegD failed");
        return FAILED;
    }


    // 此处需要根据输入类型来采取不同对齐的裁剪方式
    ret = (Result)dvpp_.Crop(cropImage, yuvImage, 0, 0, yuvImage.width-1, yuvImage.height-1);
    if (ret == FAILED) {
        ERROR_LOG("CreateInputImageData: Crop failed");
        return FAILED;
    }
    shared_ptr<ImageData> pImage = make_shared<ImageData>();
    pImage->format =cropImage.format;
    pImage->width = cropImage.width;
    pImage->height = cropImage.height;
    pImage->alignWidth = cropImage.alignWidth;
    pImage->alignHeight = cropImage.alignHeight;
    pImage->size = cropImage.size;
    pImage->data = cropImage.data;
    pImage->id = image_id;
    // 将构造好的图像数据送给线程共享队列
    ProcessDecodedImage(pImage);
    // cout << pImage->width << " " << pImage->height << endl;

    return SUCCESS;
}

void ImageNetworkReader::ProcessDecodedImage(shared_ptr<ImageData> frameData) {
    FrameImageEnQueue(frameData);
}

AtlasError ImageNetworkReader::FrameImageEnQueue(shared_ptr<ImageData> frameData) {
    for (int count = 0; count < kFrameEnQueueRetryTimes; count++) {
        if (frameImageQueue_.Push(frameData)) 
            return ATLAS_OK;
        usleep(kReadQueueOpWait); 
    }
    ATLAS_LOG_ERROR("reader %s lost read image for queue full", 
	                protocolName_.c_str());

    return ATLAS_ERROR_IMAGE_READER_QUEUE_FULL;
}

int ImageNetworkReader::color_cycle() {
    // r:0, g:1, b:2
    if (color == -1) {   // 由于Opencv是bgr所以需要反着来
        color = 2;
    }
    return color--;
}

//当前解码器是否准备好
bool ImageNetworkReader::IsOpened() { 
    ATLAS_LOG_INFO("Network %s read status %d", protocolName_.c_str(), status_);
    return (status_ == READER_READY) || (status_ == READER_START);
}

/*读取一帧解码后的yuv图像*/
AtlasError ImageNetworkReader::Read(ImageData& image) {
    //如果当前解码器异常或者解码结束,则直接返回nullptr
    if (status_ == READER_ERROR) {
        ATLAS_LOG_ERROR("Read failed for dir %s failed", 
                        protocolName_.c_str()); 
        return ATLAS_ERROR_IMAGE_READER_STATUS;
    }
    if (status_ == READER_FINISHED) {
        ATLAS_LOG_INFO("No frame to read for reader %s finished", 
                        protocolName_.c_str()); 
        return ATLAS_ERROR_READER_FINISH;
    }
    //如果当前只是准备好,但是还未开始获取网络数据，Read的调用触发接收线程开始
    if (status_ == READER_READY) {
        StartFrameReader();
        usleep(kReadQueueOpWait);
    }

    //从解码后图片存放队列读取一帧图片
    bool noWait = (status_ == READER_FINISHED);
    shared_ptr<ImageData> frame = FrameImageOutQueue(noWait);
    if ((status_ == READER_FINISHED) && (frame == nullptr)) {
        SetStatus(READER_FINISHED);
        ATLAS_LOG_INFO("No frame to read anymore");
        return ATLAS_ERROR_READER_FINISH;
    }

    if (frame == nullptr) {
        ATLAS_LOG_ERROR("No frame image to read abnormally");
        return ATLAS_ERROR_READ_EMPTY;
    }
    image = *frame;
    return ATLAS_OK;
}

shared_ptr<ImageData> ImageNetworkReader::FrameImageOutQueue(bool noWait) {

    shared_ptr<ImageData> image = nullptr;
    if (noWait) {
        image = frameImageQueue_.Pop();
    } else {
        image = frameImageQueue_.PopAndWait();
    }
    return image;
}

uint32_t ImageNetworkReader::Get(StreamProperty key) {
    uint32_t value = 0;

    switch(key){
        case FRAME_WIDTH:
            value = (uint32_t)imageWidth_;
            break;
        case FRAME_HEIGHT:
            value = (uint32_t)imageHeight_;
            break;
        default:
            ATLAS_LOG_ERROR("Unsurpport property %d to get for video", key);
            break;
    }

    return value;
}


AtlasError ImageNetworkReader::SetAclContext() {
    if (context_ == nullptr) {
        ATLAS_LOG_ERROR("Video decoder context is null");
        return ATLAS_ERROR_SET_ACL_CONTEXT;
    }
    
    aclError ret = aclrtSetCurrentContext(context_);
    if (ret != ACL_ERROR_NONE) {
        ATLAS_LOG_ERROR("Video decoder set context failed, error: %d", ret);
        return ATLAS_ERROR_SET_ACL_CONTEXT;
    }
    
    return ATLAS_OK;   
}

AtlasError ImageNetworkReader::Close() {
    DestroyResource();
    return ATLAS_OK;
}
